﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZaidimasSandelys.CustomDrawTools;
using ZaidimasSandelys.Models.DataStructures;
using ZaidimasSandelys.Models.Interfaces;
using Ninject;
using System.Windows;

namespace ZaidimasSandelys.Models.Classes
{
    /// <summary>
    /// Įvykio "Dokumentas užkrautas" argumentas 
    /// </summary>
    public class LoadCompletedEventArgs : EventArgs
    {
        /// <summary>
        /// Žmogeliukas
        /// </summary>
        public PersonVisual Person { get; private set; }

        public LoadCompletedEventArgs(PersonVisual person): base()
        {
            this.Person = person;
        }
    }

    /// <summary>
    ///  Užkrauna žaidimą iš DB ir praneša kontroleriui, kau jau užkrauta
    /// </summary>
    public class CurrentGame : ICurrentGame
    {
        private string[] _errorMessages;

        /// <summary>
        /// Klasė pakuria šitą įvykį užkrovus visus žaidimo duomenis.
        /// </summary>
        public event EventHandler<LoadCompletedEventArgs> LoadCompleted;

        private IAppData _appData;
        public GameHeader Header { get; private set; }
        private IList<AllocatedVisual> _canvas = null;
        private UInt16 _flags;
        public UInt16 _flagTest = 0x00FF;   /* Pakeisti į 0x03ff pralėtus žaidimą */
  

#if DEBUG
        /// <summary>
        /// Testavimo procedūros gali atjungti dalies elementų skaitymą
        /// </summary>
        /// <param name="flagTest"></param>
        public void SetFlagTest(UInt16 flagTest)
        {
            _flagTest = flagTest;
        }
#endif
        /// <summary>
        /// 
        /// </summary>
        /// <param name="level"></param>
        /// <param name="variant"></param>
        /// <param name="canvas"></param>
        public void LoadGame(short level, short variant, IList<AllocatedVisual> canvas)
        {
            Header = _appData.LoadGameHeader(level, variant);
            if (Header == null)
            {
                string errMessage = String.Format(_errorMessages[0], level, variant);
                MessageBoxResult result = MessageBox.Show(errMessage); 
                return;
            }
            _canvas = canvas;

            if (_canvas != null)
            {
#if DEBUG
                if ((_flagTest & 0x0001) > 0)
                    LoadAsync(Header.Id, VisualType.OuterSpace);        // Prioritetas 0
                if ((_flagTest & 0x0002) > 0)
                    LoadAsync(Header.Id, VisualType.Wall);              // Prioritetas 1
                if ((_flagTest & 0x0004) > 0)
                    LoadAsync(Header.Id, VisualType.Floor);             // Prioritetas 2
                if ((_flagTest & 0x0008) > 0)
                    LoadAsync(Header.Id, VisualType.Target);            // Prioritetas 3
                if ((_flagTest & 0x0010) > 0)
                    LoadAsync(Header.Id, VisualType.TargetHC);          // Prioritetas 4
                if ((_flagTest & 0x0020) > 0)
                    LoadAsync(Header.Id, VisualType.Container);         // Prioritetas 5
                if ((_flagTest & 0x0040) > 0)
                    LoadAsync(Header.Id, VisualType.HeavyContainer);    // Prioritetas 6
                if ((_flagTest & 0x0080) > 0)
                    LoadAsync(Header.Id, VisualType.Autocar);           // Prioritetas 7
/* Tolimesniam žaidimo plėtimui
                if ((_flagTest & 0x0040) > 0)
                    LoadAsync(Header.Id, VisualType.Keys);              // Prioritetas 7
                if ((_flagTest & 0x0040) > 0)
                    LoadAsync(Header.Id, VisualType.Doors);             // Prioritetas 8
                if ((_flagTest & 0x0040) > 0)
                    LoadAsync(Header.Id, VisualType.License);           // Prioritetas 9
 */
#else
                LoadAsync(Header.Id, VisualType.OuterSpace);
                LoadAsync(Header.Id, VisualType.Wall);
                LoadAsync(Header.Id, VisualType.Floor);
                LoadAsync(Header.Id, VisualType.Target);
                LoadAsync(Header.Id, VisualType.TargetHC);
                LoadAsync(Header.Id, VisualType.Container);
                LoadAsync(Header.Id, VisualType.HeavyContainer);
                LoadAsync(Header.Id, VisualType.Autocar);
/* Tolimesniam žaidimo plėtimui
                LoadAsync(Header.Id, VisualType.Keys);
                LoadAsync(Header.Id, VisualType.Doors);
                LoadAsync(Header.Id, VisualType.License)
 */
#endif
            }
        }

        public void ClearGame()
        {
            this.Header = null;
            this._flags = 0;
            if (this._canvas != null)
                ((DrawingCanvas)this._canvas).ClearGame();
        }

        [Inject]
        public CurrentGame(IAppData appData)
        {
            this._appData = appData;
            this._flags = 0;
            _errorMessages = _appData.GetMultilanguageConstants("LoadGame");
        }

#if DEBUG
        public IAppData AppData 
        {
            get { return _appData; }
        }
#endif
        private void LoadAsync(int gameId, VisualType elementType)
        {
            var bgWorker = new BackgroundWorker();
            bgWorker.DoWork += bgWorker_DoWork;
            bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
            bgWorker.RunWorkerAsync(new LoadAsyncRequest(gameId, elementType));
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var parameters = (LoadAsyncRequest)e.Argument;
            var rzlt = new LoadAsyncResponce(parameters)
            {
                Collection = _appData.LoadVisualElements(parameters.GameId, parameters.ElementType)
            };
            e.Result = rzlt;
        }

        /// <summary>
        /// Klaidos pranešimas naudoja fiksuotą klaidos pranešimą, kadangi klaidos galimos tik dėl duomenų
        /// bazės klaidos. Šiuo atvėju Multilanguage lenta taip pat nepasiekiama.
        /// Funkcija sukrauna į <code>_canvas</code> lauką nuskaitytus užrašus ir praneša išorinei programai
        /// kad skaitymas baigtas.
        /// </summary>
        /// <param name="sender">Siuntėjas (šiuo atvėju <code>bgWorker</code></param>
        /// <param name="e">darbo rezultatas <see cref="LoadAsyncResponce"/></param>
        private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Debug.Assert(_canvas != null);
            if (e.Error != null)
                throw new Exception("Reading data failed, please verify the 'ZaidimasSandelys.sdf' file.", e.Error);

            var data = (LoadAsyncResponce)e.Result;
            foreach (IGameElement vs in data.Collection)
            {
                // Objektas buvo sukurtas ant kito tredo, todėl reikia sukurti AllocatedVisual elementus iš
                // IGameElement elemento.
                AllocatedVisual allocatedVisual = AllocatedVisual.CreateAllocatedVisual(vs.X, vs.Y, vs.ImgTypeCode);
                if (allocatedVisual != null) 
                    _canvas.Add(allocatedVisual);
            }

            int resultBit = 0x0001 << (short)data.ElementType;
            _flags |= (UInt16)resultBit;
            if ((_flags ^ _flagTest) == 0)  // XOR operacija duoda 0 kai užkrauti visi elementų tipai išskyrus žmogeliuką
            {
                var person = (PersonVisual)AllocatedVisual.CreateAllocatedVisual(
                                            (short)Header.Person.X, (short)Header.Person.Y, (short)VisualType.Person);
                _canvas.Add(person);
                ((DrawingCanvas)_canvas).RemoveOverloads();
                if (LoadCompleted != null)
                {
                    LoadCompleted(this, new LoadCompletedEventArgs(person));
                }
            }
        }

    }
}
